package jscinttools.transmission;
/* aida libraries */
import hep.aida.IMeasurement;
import hep.aida.ref.histogram.Measurement;
/* jhplot libraries */
import jhplot.P0I;
/* java libraries */
import java.lang.Math;
import java.lang.Integer;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.File;
import jscinttools.utilities.aidautilities.AUtil;

/**
 *  Class to create RateTDC objects
 *
 * @author     Marc-Antoine Verdier
 * @created    25 janvier 2012
 */
public class RateTDCFactory{
	private RateTDCFactory(){}
	
	/**
	 *  Create a RateTDC for one file and a given segment time window
	 *
	 * @param  pathAndFile  The file (with its path) to be analysed
	 * @param  evtWindow_s  The segments duration time in seconds
	 * @return     		The created RateTDC
	 */
	public static RateTDC createRateTDC(String pathAndFile, double evtWindow_s){
		return new RateTDCImp(pathAndFile, evtWindow_s);
	}
	
	/**
	 *  Create a RateTDC for a set of files and a given segment time window
	 *
	 * @param  pathAndFile  The files (with their path) to be analysed
	 * @param  evtWindow_s  The segments duration time in seconds
	 * @return     		The created RateTDC
	 */
	public static RateTDC createRateTDC(String[] pathAndFile, double evtWindow_s){
		return new RateTDCImp(pathAndFile, evtWindow_s);
	}
}

class RateTDCImp implements RateTDC{
	private P0I[] chan;
	private final static int numChan = 7;
	private double evtWindow_s;
	
	public RateTDCImp(String pathAndFile, double evtWindow_s){
		init(evtWindow_s);
		readDataFile(pathAndFile);
	}
	
	public RateTDCImp(String[] pathAndFile, double evtWindow_s){
		init(evtWindow_s);
		for (int i = 0; i < pathAndFile.length; i++){
			readDataFile(pathAndFile[i]);
		}
	}
	
	private void init(double evtWindow_s){
		this.evtWindow_s = evtWindow_s;
		this.chan = new P0I[numChan];
		for (int i = 0; i < numChan; i++){
			chan[i] = new P0I("Ch" + (i + 1));
		}
	}
	
	private void readDataFile(String pathAndFile){
		TDCDFR file = new TDCDFR(pathAndFile);
		file.readFile();
	}
	
	private class TDCDFR{
		private String pathAndFile;
		private boolean newEvt;
		private boolean first;
		private int[] cnt;
		
		public TDCDFR(String pathAndFile){
			this.pathAndFile = pathAndFile;
			initNewEvt();
			this.first = true;
		}
		
		private void initNewEvt(){
			this.newEvt = true;
			this.cnt = new int[numChan];
			for (int i = 0; i < numChan; i++){
				cnt[i] = 0;
			}
		}
		
		public void readFile(){
			try{
				InputStream ips = new FileInputStream(pathAndFile);
					InputStreamReader ipsr = new InputStreamReader(ips);
					BufferedReader br = new BufferedReader(ipsr);
					String line;
					while ((line = br.readLine()) != null){
						if (!line.startsWith("#"))
							checkNewEvt(line);
					}
					br.close(); 
			}		
			catch (Exception e){
				System.out.println(e.toString());
			}
		}
		
		private void checkNewEvt(String line){
			String[] val = line.split("\t");
			int c0 = Integer.parseInt(val[0]);
			if (c0 == 0)
				newEvent();
			else
				cnt[c0 - 1]++;
		}
	
		private void newEvent(){
			if (!first)
				fillP0Is();
			this.first = false;
			initNewEvt();
		}
		
		private void fillP0Is(){
			for (int i = 0; i < numChan; i++){
				chan[i].add(cnt[i]);
			}
		}
	}
	
	public int segmentsTotal(){
		return chan[0].size();
	}
	
	public int segments(){
		int cnt = 0;
		for (int i = 0; i < chan[numChan - 1].size(); i++){
			if (chan[numChan - 1].get(i) == 0)
				cnt ++;
		}
		return cnt;
	}
	
	public int countsTotal(int ch){
		int sum = 0;
		int size = chan[ch - 1].size();
		for (int i = 0; i < size; i++){
			sum += chan[ch - 1].get(i);
		}
		return sum;
	}
	
	public int counts(int ch){
		int sum = 0;
		int size = chan[ch - 1].size();
		for (int i = 0; i < size; i++){
			if (chan[numChan - 1].get(i) == 0)
				sum += chan[ch - 1].get(i);
		}
		return sum;
	}
	
	public IMeasurement rateTotal(int ch){
		return calcRate(countsTotal(ch), segmentsTotal());
	}
	
	public IMeasurement rate(int ch){
		int sum = 0;
		int cnt = 0;
		for (int i = 0; i < segmentsTotal(); i++){
			if (chan[numChan - 1].get(i) == 0){
				sum += chan[ch - 1].get(i);
				cnt ++;
			}
		}
		return calcRate(sum, cnt);
	}
	
	private IMeasurement calcRate(int sum, int cnt){
		double totTime = (double) cnt * evtWindow_s;
		double rate = (double) sum / totTime;
		double rateErr = Math.sqrt((double) sum) / totTime; 
		return new Measurement(rate, rateErr);
	}
	
	public IMeasurement rate(int ch, IMeasurement drkCountsRate){
		IMeasurement rate = rate(ch);
		return AUtil.substract(rate, drkCountsRate);
	}
	
	public IMeasurement rate(int ch, RateTDC drkCountsRate){
		return rate(ch, drkCountsRate.rate(ch));
	}
	
	public IMeasurement rateRatio(int ch1, int ch2, RateTDC drkCountsRate){
		return rateRatio(ch1, drkCountsRate.rate(ch1), ch2, drkCountsRate.rate(ch2));
	}
	
	public IMeasurement rateRatio(int ch1, IMeasurement drkCountsRate1, int ch2, IMeasurement drkCountsRate2){
		IMeasurement rate1 = rate(ch1, drkCountsRate1);
		IMeasurement rate2 = rate(ch2, drkCountsRate2);
		return AUtil.divide(rate1, rate2);
	}
}
